package games.catchTheCreature;


import java.util.ArrayList;
import java.util.HashMap;

import commonDataStructures.GridList;


public class Heuristic {

	private static GridList<HashMap<String, Integer>> _map=null; 
	private boolean _isAStar=false;
	
	public void setAStart(){
		_isAStar=true;
	}
	private void initDistMap(CTCBoard  world){
		_map = new GridList<HashMap<String,Integer>>(world.getWidth(),world.getHeight());
		for(int x=0;x<_map.getWidth();x++){
			for(int y=0;y<_map.getHeight();y++){
				_map.set(y, x, new HashMap<String, Integer>());
			}
		}
	}


	private void fillDistMap(CTCBoard world,GridList<Integer> map,Point p){
		int dist=0;
		ArrayList<Point> pList = new ArrayList<Point>();
		pList.add(p);
		while (!pList.isEmpty()){
			ArrayList<Point> tmpPList = new ArrayList<Point>();
			while (!pList.isEmpty()){
				Point tmpP = pList.remove(0);
				if (map.get(tmpP.getY(), tmpP.getX())==-2&& world.canPlayerStepOn(tmpP.getX(),tmpP.getY())){
					map.set(tmpP.getY(),tmpP.getX(),dist);
					tmpPList.add(new Point(tmpP.getX()+1,tmpP.getY()));
					tmpPList.add(new Point(tmpP.getX()-1,tmpP.getY()));
					tmpPList.add(new Point(tmpP.getX(),tmpP.getY()+1));
					tmpPList.add(new Point(tmpP.getX(),tmpP.getY()-1));
				}
			}
			dist++;
			while (!tmpPList.isEmpty()){
				Point tmpP = tmpPList.remove(0);
				if (world.canPlayerStepOn(tmpP.getX(),tmpP.getY())&&map.get(tmpP.getY(),tmpP.getX())==-2){
					pList.add(tmpP);
				}
			}
		}
	}

	private void updateMainMap(GridList<Integer> distMap,Point p){
		for(int x=0;x<distMap.getWidth();x++){
			for(int y=0;y<distMap.getHeight();y++){
				_map.get(p.getY(),p.getX()).put(String.valueOf(x)+"#"+String.valueOf(y), distMap.get(y, x));
			}
		}
	}


	private void buildDistMap(CTCBoard world){

		for(int x=0;x<world.getWidth();x++){
			for(int y=0;y<world.getHeight();y++){
				GridList<Integer> distMap = world.getArrMap();
				if (distMap.get(y, x)==-1){
					continue;
				}
				fillDistMap(world, distMap, new Point(x,y));
				updateMainMap(distMap,new Point(x,y));
				
				if (x==0 && y==0){
					System.out.println(distMap.get(0, 0));
				}
			}
		}
	}

	public Heuristic(CTCBoard  world){
		if (_map==null){
			initDistMap(world);
			buildDistMap(world);
		}
	}
	
	/*private ArrayList<Point> getMoves(CTCState state,Point p){
		ArrayList<Point> res = new ArrayList<Point>();
		res.add(new Point(p.getX()+1,p.getY()));
		res.add(new Point(p.getX(),p.getY()+1));
		res.add(new Point(p.getX()-1,p.getY()));
		res.add(new Point(p.getX(),p.getY()-1));
		for(int i=3;i>=0;i--){
			Point tmp = res.get(i);
			if (!state.getWorld().canStepOn(tmp)||state.getWorld().get(tmp.getY(), tmp.getX())==CTCSquare.PLAYER){
				res.remove(i);
			}
		}
		return res;
	}
	
	private ArrayList<Point> getCreatureMoves(CTCState state){
		return getMoves(state, state.getWorld().getCreaturePoint());
	}
	
	private ArrayList<Point> getPlayerMoves(CTCState state){
		return getMoves(state, state.getWorld().getPlayerPoint());
	}
	
	private double getExpectation(CTCState state){
		ArrayList<Point> p = getPlayerMoves(state);
		ArrayList<Point> c = getCreatureMoves(state);
		double e=0.;
		for(Point ppt:p){
			double tmp=0.;
			for(Point cpt:c){
				tmp+=getDistance(cpt, ppt);
			}
			e+=tmp/c.size();
		}
		return e/p.size();
	}*/
	
	private int getBlocsAroundTheCreature(CTCState state){
		Point p = state.getWorld().getCreaturePoint();
		int block = 0;
		if (!state.getWorld().canStepOn(p.getX()+1, p.getY())){
			block++;
		}
		if (!state.getWorld().canStepOn(p.getX(), p.getY()+1)){
			block++;
		}
		if (!state.getWorld().canStepOn(p.getX(), p.getY()-1)){
			block++;
		}
		if (!state.getWorld().canStepOn(p.getX()-1, p.getY())){
			block++;
		}
		return block;
	}
	
	public Double getRank(CTCState state){
		if ((double)getDistance(new Point(state.getWorld().getCreaturePoint()), new Point(state.getWorld().getPlayerPoint()))+(4-getBlocsAroundTheCreature(state)) < 0){
			int a=5;
			a++;
		}
		double dist = (double)getDistance(new Point(state.getFather().getWorld().getCreaturePoint()), new Point(state.getWorld().getPlayerPoint()));
		int free = (4-getBlocsAroundTheCreature(state));
		if (!_isAStar){
			return dist*2+free;
		}else{
			return dist*2+free+state.getDepth();
		}
	}
	
	public int getDistance(Point p1,Point p2){
		int dist = _map.get(p1.getY(), p1.getX()).get(String.valueOf(p2.getX())+"#"+String.valueOf(p2.getY()));
		return dist;
		
	}
	
	
}
